package design.pattern.Lu18MementoPattern;

import lombok.Data;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @program JavaBase
 * @description: 备忘录模式
 *    多状态，备忘录(反射设置值，回退初始态)
 * @author: zhanglu
 * @create: 2020-04-10 16:30:00
 */
public class MementoPattern04 {

   public static void main(String[] args) {
      Originator04 originator04 = new Originator04();
      Caretaker04 caretaker04 = new Caretaker04();
      originator04.setState01("1");
      originator04.setState02("2");
      originator04.setState03("3");

      System.out.println(originator04.toString());

      caretaker04.setMemento04(originator04.createMemento());

      originator04.setState01("4");
      originator04.setState02("5");
      originator04.setState03("6");
      System.out.println(originator04.toString());

      originator04.restoreMemento(caretaker04.getMemento04());
      System.out.println(originator04.toString());

   }

}

@Data
class Originator04{

   private String state01;
   private String state02;
   private String state03;

   public Memento04 createMemento(){
      return new Memento04(BeanUtils.backupProp(this));
   }

   public void restoreMemento(Memento04 memento04){
      BeanUtils.restoreProp(this, memento04.getStateMap());
   }

   @Override
   public String toString() {
      return "Originator04{" +
              "state01='" + state01 + '\'' +
              ", state02='" + state02 + '\'' +
              ", state03='" + state03 + '\'' +
              '}';
   }
}

@Data
class Memento04{

   private Map<String, Object> stateMap;

   public Memento04(Map<String, Object> stateMap) {
      this.stateMap = stateMap;
   }

}

@Data
class Caretaker04{
   private Memento04 memento04;
}

class BeanUtils{

   public static Map<String, Object> backupProp(Object obj){
      Map<String, Object> res = new HashMap<>();
      try {
         BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
         PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
         for (PropertyDescriptor descriptor : propertyDescriptors) {
            String fieldName = descriptor.getName();
            Method readMethod = descriptor.getReadMethod();
            Object fieldValue = readMethod.invoke(obj, new Object[]{});
            if(!fieldName.equalsIgnoreCase("class")){
               res.put(fieldName, fieldValue);
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      return res;
   }

   public static void restoreProp(Object obj, Map<String, Object> propMap){
      try {
         BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
         PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
         for (PropertyDescriptor descriptor : propertyDescriptors) {
            String fieldName = descriptor.getName();
            if(propMap.containsKey(fieldName)){
               Method writeMethod = descriptor.getWriteMethod();
               Object o = writeMethod.invoke(obj, new Object[]{propMap.get(fieldName)});
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

}

